﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using Cabal.Kernel.DataSet;
using Cabal.Kernel.Consts;
using System.Threading;

namespace Cabal.Kernel.Output
{
    /// <summary>
    /// CabalSoul任务管理核心
    /// </summary>
    public class MissionManager
    {
        public MissionManager(CabalSoul kernel)
        {
            _kernel = kernel;
            _rulectrl = new RuleControl(_kernel, kernel.Settings.ReadString(Cabal.Kernel.Provider.Setting.KEY_RulePath));
            _rulectrl.ReadXML();

            _Unstart = new PriorityQueue7<Mission>();
            _OwnerSleeped = new Queue<MissionOwner>();
            _Running = new MissionCollection();
            _Result = new MissionCollection();
            _RThread = new List<WorkingThreadInfo>();
        }

        CabalSoul _kernel;
        RuleControl _rulectrl;

        List<WorkingThreadInfo> _RThread;
        PriorityQueue7<Mission> _Unstart;
        Queue<MissionOwner> _OwnerSleeped;
        MissionCollection _Running;
        MissionCollection _Result;

        public MissionCollection RunningMission
        {
            get { return _Running; }
        }

        //常量设定
        public int MaxResultBuffer = 100;
        public int MaxUnstartBuffer = 50;
        public int MaxSleepThreadBuffer = 30; //可能重复,设置的大一些
        public int MaxNomalThread = 10;
        public int MaxRealtimeThread = 10;

        Mutex Mutex_AddMission = new Mutex(); //添加任务时互斥体
        public void AddMission(Mission m)
        {
            //线程同步锁定
            Mutex_AddMission.WaitOne(); //启用互斥体
            Monitor.Enter(_Running);
            Monitor.Enter(_RThread);
            Monitor.Enter(_Unstart);

            try
            {
                if (_Unstart.Count >= MaxUnstartBuffer)
                {
                    Mutex_AddMission.ReleaseMutex(); //释放互斥体
                    Monitor.Exit(_Running);
                    Monitor.Exit(_RThread);
                    Monitor.Exit(_Unstart);
                    throw new MissionMagagerException(MMagagerErrorCode.Add_BufferFull);
                }

                if (_rulectrl.Check(m) == CheckResult.Match)
                {
                    Mutex_AddMission.ReleaseMutex(); //释放互斥体
                    Monitor.Exit(_Running);
                    Monitor.Exit(_RThread);
                    Monitor.Exit(_Unstart);
                    throw new MissionMagagerException(MMagagerErrorCode.Add_RequestDeny);
                }


                //加入等待队列
                _Unstart.Enqueue(m, m.PriorityLevel);

                //开启线程
                int nowcount = _RThread.Count;
                if (nowcount < MaxNomalThread)
                {
                    for (int i = 0, n = Math.Min(MaxNomalThread - nowcount, _Unstart.Count); i < n; i++)
                    {
                        NewNomalThread();
                    }
                }
            }
            finally
            {
                Mutex_AddMission.ReleaseMutex(); //释放互斥体
                Monitor.Exit(_Running);
                Monitor.Exit(_RThread);
                Monitor.Exit(_Unstart);
            }

        }
        public bool AddMissionTry(Mission m)
        {
            try
            {
                AddMission(m);
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 增加一个任务。如果任务不可追加，则直到任务可以追加前会阻塞调用线程。
        /// </summary>
        public void AddMissionWait(Mission m)
        {
            while (AddMissionTry(m) == false)
            {
                try
                {
                    _OwnerSleeped.Enqueue(m.Owner); //添加到睡眠线程列表
                    Thread.Sleep(Timeout.Infinite); //永久睡眠
                }
                catch (Exception e)
                {
                    if (!(e is ThreadInterruptedException))
                        throw e;
                }
            }
        }
        public bool AddMissionWait(Mission m, int timeout, int trycount)
        {
            for (int i = 0; i < trycount; i++)
            {
                if (AddMissionTry(m) == false)
                {
                    try //添加失败，等待
                    {
                        _OwnerSleeped.Enqueue(m.Owner); //添加到睡眠线程列表
                        Thread.Sleep(timeout);
                    }
                    catch (Exception e)
                    {
                        if (!(e is ThreadInterruptedException)) //如果是唤醒则继续 否则抛出错误
                            throw e;
                    }
                }
                else
                {
                    return true; //成功添加
                }
            }
            return false;
        }
        
        /// <summary>
        /// 执行实时任务
        /// </summary>
        public void RealtimeMission(Mission m)
        {
            throw new NotImplementedException();
        }


        void NewNomalThread()
        {
            WorkingThreadInfo wt = new WorkingThreadInfo();
            wt.thread = new Thread(new ParameterizedThreadStart(ThreadMain));
            wt.thread.IsBackground = true;
            _RThread.Add(wt);

            wt.thread.Start(wt as object);
        }

        bool AllowRun = true;
        void ThreadMain(object threadinfo)
        {
            //throw new NotImplementedException();

            Mission now;
            WorkingThreadInfo info = threadinfo as WorkingThreadInfo;
            while (AllowRun)
            {
                //获得任务
                now = getMission();
                if (now == null) break;

                //注册线程
                info.mission = now;

                //执行任务
                now.Data.DoWork();

                //任务结束参数
                MissionEventArgs e = new MissionEventArgs();
                e.message = "任务结束";
                e.mission = now;
                e.workingThread = info.thread;

                //通知
                lock(now.Owner)
                    now.Owner.StartNotice(this, e);

                //唤醒
                weakUpThread();

                //去除
                info.mission = null;
            }
        }

        Mission getMission()
        {
            Monitor.Enter(_Unstart);

            try
            {
                if (_Unstart.Count > 0)
                {
                    Mission now = null;
                    now = _Unstart.Dequeue();

                    Monitor.Exit(_Unstart);
                    return now;
                }
            }
            catch { }

            Monitor.Exit(_Unstart);
            return null;
        }
        void weakUpThread()
        {
            Monitor.Enter(_OwnerSleeped);

            try
            {
                while (_OwnerSleeped.Count > 0)
                {
                    MissionOwner owner = _OwnerSleeped.Dequeue();
                    if (owner.MainThread.ThreadState == ThreadState.WaitSleepJoin)
                    {
                        owner.MainThread.Interrupt(); //唤醒
                        break;
                    }
                }
            }
            catch { }

            Monitor.Exit(_OwnerSleeped);
        }
    }

    public class WorkingThreadInfo
    {
        public Thread thread;
        public Mission mission;
    }

    /// <summary>
    /// 任务管理核心异常
    /// </summary>
    public class MissionMagagerException : Exception
    {
        public MissionMagagerException(MMagagerErrorCode code) : base()
        {
            ErrorCode = code;
        }

        public MissionMagagerException(MMagagerErrorCode code, string msg)
            : base(msg)
        {
            ErrorCode = code;
        }

        public MMagagerErrorCode ErrorCode;
    }

    /// <summary>
    /// 任务管理核心异常的错误编码
    /// </summary>
    public enum MMagagerErrorCode
    {
        Add_BufferFull,
        Add_IPRequestFull,
        Add_RequestDeny,
    }
}